package com.gitee.srurl.core.util;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.gitee.srurl.core.constant.JsonConstant;
import com.gitee.srurl.core.exception.JsonException;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.List;

/**
 * @author zxw
 * @date 2023/4/10 22:39
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public abstract class JacksonUtil {


    private static final ObjectMapper objectMapper;

    private static final String EMPTY_STR = "";
    private static final byte[] EMPTY_ARRAY = new byte[0];

    static {
        objectMapper = new ObjectMapper();
        // 反序列化时，json中包含pojo不存在的字段时，不报错
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.registerModule(new JavaTimeModule());
    }

    public static String toJsonString(Object object) {

        if (isBlank(object)) {
            return EMPTY_STR;
        }

        try {
            return objectMapper.writeValueAsString(object);
        } catch (Exception e) {
            log.error("转json字符串出现异常：", e);
            throw new JsonException("序列化异常");
        }
    }

    public static byte[] toJsonByte(Object object) {

        if (isBlank(object)) {
            return EMPTY_ARRAY;
        }

        try {
            return objectMapper.writeValueAsBytes(object);
        } catch (Exception e) {
            log.error("转json字符串出现异常：", e);
            throw new JsonException();
        }
    }

    public static <T> T parseObject(String text, Class<T> clazz) {

        AssertUtil.notBlank(text, "解析数据不能为空！");

        try {

            return objectMapper.readValue(text, clazz);
        } catch (Exception e) {
            log.error("解析json字符串出现异常：", e);
            throw new JsonException("反序列化异常");
        }
    }

    public static <T> T parseObject(byte[] data, Class<T> clazz) {

        AssertUtil.notEmpty(data, "解析数据不能为空！");

        try {

            return objectMapper.readValue(data, clazz);
        } catch (Exception e) {
            log.error("解析json字符串出现异常：", e);
            throw new JsonException("反序列化异常");
        }
    }

    public static <T> T parseObject(byte[] data, TypeReference<T> typeReference) {

        AssertUtil.notEmpty(data, "解析数据不能为空！");

        try {

            return objectMapper.readValue(data, typeReference);
        } catch (Exception e) {
            log.error("解析json字符串出现异常：", e);
            throw new JsonException("反序列化异常");
        }
    }

    public static <T> T parseObject(String text, TypeReference<T> typeReference) {

        AssertUtil.notBlank(text, "解析数据不能为空！");
        try {
            return objectMapper.readValue(text, typeReference);
        } catch (Exception e) {
            log.error("解析json字符串出现异常：", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 解析json 支持 array 和 object 的解析
     *
     * @param text 解析的 json 数据
     * @return 反序列化后的数据
     */
    public static Object parseObjectOrArray(String text) {

        AssertUtil.notBlank(text, "解析数据不能为空！");

        if (StrUtil.startWith(text, JsonConstant.ARRAY_BEGIN)) {
            // 说明是数组
            return JacksonUtil.parseArray(text, Object.class);
        } else if (StrUtil.startWith(text, JsonConstant.OBJECT_BEGIN)) {
            // 说明是对象
            return JacksonUtil.parseObject(text, new TypeReference<>() {
            });
        } else {
            // 未知类型 原数据不替换
            return text;
        }
    }

    public static <T> List<T> parseArray(String text, Class<T> clazz) {

        AssertUtil.notBlank(text, "解析数据不能为空！");

        try {
            return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
        } catch (Exception e) {
            log.error("解析json字符串出现异常：", e);
            throw new RuntimeException(e);
        }
    }

    public static <T> List<T> parseArray(byte[] data, Class<T> clazz) {

        AssertUtil.notEmpty(data, "解析数据不能为空！");
        try {
            return objectMapper.readValue(data, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
        } catch (Exception e) {
            log.error("解析json字符串出现异常：", e);
            throw new RuntimeException(e);
        }
    }

    public static void writeFile(byte[] data, String path) {

        AssertUtil.notEmpty(data, "解析数据不能为空！");
        AssertUtil.notBlank(path, "路径不能为空！");

        try (FileOutputStream fileOutputStream = new FileOutputStream(path)) {
            objectMapper.writeValue(fileOutputStream, data);
        } catch (Exception e) {
            log.error("写入json文件出现异常：", e);
            throw new RuntimeException(e);
        }
    }

    public static void writeFile(Object data, String path) {

        AssertUtil.nonNull(data, "解析数据不能为空！");
        AssertUtil.notBlank(path, "路径不能为空！");

        try (FileOutputStream fileOutputStream = new FileOutputStream(path)) {
            objectMapper.writeValue(fileOutputStream, data);
        } catch (Exception e) {
            log.error("写入json文件出现异常：", e);
            throw new RuntimeException(e);
        }
    }

    public static <T> void readFile(String path, Class<T> clazz) {

        AssertUtil.notBlank(path, "路径不能为空！");

        try (FileInputStream fileOutputStream = new FileInputStream(path)) {
            objectMapper.readValue(fileOutputStream, clazz);
        } catch (Exception e) {
            log.error("解析json文件出现异常：", e);
            throw new RuntimeException(e);
        }
    }

    private static boolean isBlank(Object data) {

        if (data == null) {
            return true;
        }

        if (data instanceof String str) {

            return StrUtil.isBlank(str);
        }

        return false;
    }
}
